#pragma once

#include <vex/iterable/range_state.h>
#include <utility>

namespace vex { namespace iterable { namespace adapter {

    class adapter_access {
    public:
        /// <summary>
        /// Access l-value reference of the adaptee given the instance of adapter base class
        /// </summary>
        template<class TAdapter, class TAdapterBase> 
        static typename TAdapter::adaptee_type& get_adaptee_ref(TAdapterBase& p_adapter_base)
        {
            return static_cast<TAdapter&>(p_adapter_base)
                .get_adaptee_ref();
        }

        /// <summary>
        /// Access l-value reference to constant adaptee given the instance of adapter base class
        /// </summary>
        template<class TAdapter, class TAdapterBase> 
        static typename TAdapter::adaptee_type const& get_adaptee_ref(TAdapterBase const& p_adapter_base)
        {
            return static_cast<TAdapter const&>(p_adapter_base)
                .get_adaptee_ref();
        }

        template<class TAdapter, class TAdapterBase> 
        static TAdapter construct_from_saved( TAdapterBase const& p_adapter_base )
        {
            return TAdapter(static_cast<TAdapter const&>(p_adapter_base)
                .get_adaptee_ref()
                .save());
        }

        //template <class TAdapter, class TValue>
        //static bool put(TAdapter * p_adapter, TValue && p_value)
        //{
        //    return p_adapter->get_adaptee_ref().put(std::forward<TValue>(p_value));
        //}

        //template <class TAdapter>
        //static range_state const & get_state(TAdapter const * p_adapter)
        //{
        //    return p_adapter->get_adaptee_ref().get_state();
        //}

        //template <class TAdapter>
        //static TAdapter save(TAdapter const * p_adapter)
        //{
        //    return p_adapter->get_adaptee_ref().save();
        //}

        //template <class TAdapter>
        //static typename TAdapter::reference front(TAdapter const * p_adapter)
        //{
        //    return p_adapter->get_adaptee_ref().front();
        //}

        //template <class TAdapter>
        //static typename TAdapter::reference back(TAdapter const * p_adapter)
        //{
        //    return p_adapter->get_adaptee_ref().back();
        //}

        //template <class TAdapter>
        //static bool move_front(TAdapter * p_adapter)
        //{
        //    return p_adapter->get_adaptee_ref().move_front();
        //}

        //template <class TAdapter>
        //static bool move_back(TAdapter * p_adapter)
        //{
        //    return p_adapter->get_adaptee_ref().move_back();
        //}

        //template <class TAdapter>
        //static bool move_front_of(TAdapter * p_adapter, std::size_t p_diff)
        //{
        //    return p_adapter->get_adaptee_ref().move_front_of(p_diff);
        //}

        //template <class TAdapter>
        //static bool move_back_of(TAdapter * p_adapter, std::size_t p_diff)
        //{
        //    return p_adapter->get_adaptee_ref().move_back_of(p_diff);
        //}

        //template <class TAdapter>
        //static std::size_t size(TAdapter const * p_adapter)
        //{
        //    return p_adapter->get_adaptee_ref().size();
        //}

        //template <class TAdapter>
        //static typename TAdapter::reference at(TAdapter const * p_adapter, std::size_t p_diff)
        //{
        //    return p_adapter->get_adaptee_ref().at(p_diff);
        //}
    };
}}}